package com.ethink.warehouse.facade.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ethink.framework.common.constant.CommonRespCode;
import com.ethink.framework.common.exception.BusinessException;
import com.ethink.framework.common.web.context.SPRequestContextHolder;
import com.ethink.id.generator.IdGenerator;
import com.ethink.warehouse.api.MateInventoryOtherOutLogFacade;
import com.ethink.warehouse.api.enums.LogisticsTraceDetailOrderTypeEnum;
import com.ethink.warehouse.api.enums.MateInventoryOtherOutLogOrderStatusEnum;
import com.ethink.warehouse.api.enums.SubjectEnum;
import com.ethink.warehouse.api.info.MateInventoryOtherOutLogInfo;
import com.ethink.warehouse.api.info.MateInventoryOtherOutLogModeInfo;
import com.ethink.warehouse.api.request.*;
import com.ethink.warehouse.api.response.MateInventoryOtherOutLogAddResponse;
import com.ethink.warehouse.api.response.MateInventoryOtherOutLogDeleteResponse;
import com.ethink.warehouse.api.response.MateInventoryOtherOutLogDetailResponse;
import com.ethink.warehouse.api.response.MateInventoryOtherOutLogUpdateResponse;
import com.ethink.warehouse.common.entity.MateInventoryOtherOutLog;
import com.ethink.warehouse.common.entity.MateInventoryOtherOutLogDetail;
import com.ethink.warehouse.common.mapper.MateInventoryOtherOutLogDetailMapper;
import com.ethink.warehouse.common.mapper.MateInventoryOtherOutLogMapper;
import com.ethink.warehouse.manager.MateInventoryManager;
import com.ethink.warehouse.service.MateInventoryOtherOutLogDetailService;
import com.ethink.warehouse.service.MateInventoryOtherOutLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 其他出库 Facade接口实现
 *
 * @author default
 * @date 2023-02-08
 */
@RestController
@Slf4j
@RequestMapping("warehouse-service/facade/v1/mateInventoryOtherOutLog")
public class MateInventoryOtherOutLogFacadeImpl implements MateInventoryOtherOutLogFacade {

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private MateInventoryOtherOutLogService mateInventoryOtherOutLogService;

    @Autowired
    private MateInventoryOtherOutLogDetailService mateInventoryOtherOutLogDetailService;

    @Autowired
    private MateInventoryOtherOutLogMapper mateInventoryOtherOutLogMapper;

    @Autowired
    private MateInventoryOtherOutLogDetailMapper mateInventoryOtherOutLogDetailMapper;

    @Autowired
    private MateInventoryManager mateInventoryManager;


    @Override
    public Page<MateInventoryOtherOutLogInfo> queryMateInventoryOtherOutLog(MateInventoryOtherOutLogQueryRequest request) {
        return mateInventoryOtherOutLogService.queryMateInventoryOtherOutLog(request);
    }

    @Override
    public MateInventoryOtherOutLogDetailResponse getMateInventoryOtherOutLogById(Long mateInventoryOtherOutLogId) {
        return mateInventoryOtherOutLogService.getMateInventoryOtherOutLogById(mateInventoryOtherOutLogId);
    }

    @Override
    public List<MateInventoryOtherOutLogInfo> listMateInventoryOtherOutLog(MateInventoryOtherOutLogQueryRequest request) {
        return mateInventoryOtherOutLogService.listMateInventoryOtherOutLog(request);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MateInventoryOtherOutLogAddResponse addMateInventoryOtherOutLog(MateInventoryOtherOutLogAddRequest request) {
        request.setOrderNo(idGenerator.ock());
        request.setOrderStatus(MateInventoryOtherOutLogOrderStatusEnum.S2.getIntValue());
        request.setCreateUserCode(SPRequestContextHolder.getCurrentSystemUserLoginName());
        request.setCreateUserName(SPRequestContextHolder.getCurrentSystemUserRealName());
        // 添加明细表
        List<MateInventoryOtherOutLogDetailAddRequest> childrenRequestList = request.getItems();
        List<MateInventoryOtherOutLogDetail> childrenList = new ArrayList<>();
        childrenRequestList.forEach(item -> {
            MateInventoryOtherOutLogDetail children = new MateInventoryOtherOutLogDetail();
            BeanUtil.copyProperties(item, children, true);
            children.setOrderNo(request.getOrderNo());
            children.setCreateUser(request.getCreateUserName());
            children.setIsDeleted(Boolean.FALSE);
            children.setCreateTime(LocalDateTime.now());
            children.setUpdateTime(LocalDateTime.now());
            childrenList.add(children);
        });
        Boolean aBoolean = mateInventoryOtherOutLogDetailService.addMateInventoryOtherOutLogDetailList(childrenList);
        if (!aBoolean) {
            throw new RuntimeException("新增明细失败");
        }
        MateInventoryOtherOutLogAddResponse mateInventoryOtherOutLogAddResponse = mateInventoryOtherOutLogService.addMateInventoryOtherOutLog(request);
        if (ObjectUtils.isEmpty(mateInventoryOtherOutLogAddResponse)) {
            throw new RuntimeException("新增失败");
        }
        if (MateInventoryOtherOutLogOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            lock(mateInventoryOtherOutLogAddResponse.getId());
        }
        return mateInventoryOtherOutLogAddResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MateInventoryOtherOutLogUpdateResponse updateMateInventoryOtherOutLog(MateInventoryOtherOutLogUpdateRequest request) {
        MateInventoryOtherOutLogUpdateResponse response = mateInventoryOtherOutLogService.updateMateInventoryOtherOutLog(request);
        if (MateInventoryOtherOutLogOrderStatusEnum.S2.eq(request.getOrderStatus())) {
            lock(response.getId());
        }
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteMateInventoryOtherOutLog(Long mateInventoryOtherOutLogId) {
        MateInventoryOtherOutLog changeLog = mateInventoryOtherOutLogMapper.selectById(mateInventoryOtherOutLogId);
        if (MateInventoryOtherOutLogOrderStatusEnum.S3.eq(changeLog.getOrderStatus())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "订单已完成，无法撤销");
        }
        if (MateInventoryOtherOutLogOrderStatusEnum.S2.eq(changeLog.getOrderStatus())) {
            // 需要释放库存
            List<MateInventoryOtherOutLogDetail> changeLogDetails = mateInventoryOtherOutLogDetailMapper.selectList(
                    new LambdaQueryWrapper<MateInventoryOtherOutLogDetail>()
                            .eq(MateInventoryOtherOutLogDetail::getOrderNo, changeLog.getOrderNo())
            );
            releaseLock(changeLog, changeLogDetails);
        }

        return mateInventoryOtherOutLogService.deleteMateInventoryOtherOutLog(mateInventoryOtherOutLogId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean mateInventoryOtherOutLogPass(Long mateInventoryOtherOutLogId) {
        MateInventoryOtherOutLog changeLog = mateInventoryOtherOutLogService.selectMateInventoryOtherOutLogById(mateInventoryOtherOutLogId);
        if (!MateInventoryOtherOutLogOrderStatusEnum.S2.eq(changeLog.getOrderStatus())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "当前订单状态无法审批通过");
        }
        mateInventoryOtherOutLogService.mateInventoryOtherOutLogPass(mateInventoryOtherOutLogId);
        List<MateInventoryOtherOutLogDetail> changeLogDetails = mateInventoryOtherOutLogDetailMapper.selectList(
                new LambdaQueryWrapper<MateInventoryOtherOutLogDetail>()
                        .eq(MateInventoryOtherOutLogDetail::getOrderNo, changeLog.getOrderNo())
        );
        releaseLock(changeLog, changeLogDetails);
        // 出库
        mateInventoryManager.otherOut(changeLog, changeLogDetails);
        return mateInventoryOtherOutLogService.mateInventoryOtherOutLogPass(mateInventoryOtherOutLogId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean mateInventoryOtherOutLogRefuse(Long mateInventoryOtherOutLogId) {
        MateInventoryOtherOutLog mateInventoryOtherOutLog = mateInventoryOtherOutLogService.selectMateInventoryOtherOutLogById(mateInventoryOtherOutLogId);
        if (!MateInventoryOtherOutLogOrderStatusEnum.S2.eq(mateInventoryOtherOutLog.getOrderStatus())) {
            throw new BusinessException(CommonRespCode.SYSTEM_ERR, "当前订单状态无法审批拒绝");
        }
        List<MateInventoryOtherOutLogDetail> changeLogDetails = mateInventoryOtherOutLogDetailMapper.selectList(
                new LambdaQueryWrapper<MateInventoryOtherOutLogDetail>()
                        .eq(MateInventoryOtherOutLogDetail::getOrderNo, mateInventoryOtherOutLog.getOrderNo())
        );
        releaseLock(mateInventoryOtherOutLog, changeLogDetails);
        return mateInventoryOtherOutLogService.mateInventoryOtherOutLogRefuse(mateInventoryOtherOutLogId);
    }

    private void lock(Long id) {
        // 锁定库存
        MateInventoryOtherOutLog changeLog = mateInventoryOtherOutLogMapper.selectById(id);
        List<MateInventoryOtherOutLogDetail> changeLogDetails = mateInventoryOtherOutLogDetailMapper.selectList(
                new LambdaQueryWrapper<MateInventoryOtherOutLogDetail>()
                        .eq(MateInventoryOtherOutLogDetail::getOrderNo, changeLog.getOrderNo())
        );
        List<MateInventoryLockLogAddRequest> requests = new ArrayList<>();
        for (MateInventoryOtherOutLogDetail changeLogDetail : changeLogDetails) {
            MateInventoryLockLogAddRequest request = new MateInventoryLockLogAddRequest();
            request.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
            request.setSourceOrderNo(changeLog.getOrderNo());
            request.setSourceDetailOrderNo(changeLog.getOrderNo() + changeLogDetail.getId());
            request.setSourceOrderType(SubjectEnum.T132.getCode());
            request.setSubject(SubjectEnum.T132.getCode());
            request.setMateInventoryId(changeLogDetail.getMateInventoryId());
            request.setLockQty(changeLogDetail.getQty());
            requests.add(request);
        }
        mateInventoryManager.lockMateInventory(requests);
    }

    private void releaseLock(MateInventoryOtherOutLog changeLog, List<MateInventoryOtherOutLogDetail> changeLogDetails) {
        List<MateInventoryLockLogAddRequest> requests = new ArrayList<>();
        for (MateInventoryOtherOutLogDetail changeLogDetail : changeLogDetails) {
            MateInventoryLockLogAddRequest request = new MateInventoryLockLogAddRequest();
            request.setOrderType(LogisticsTraceDetailOrderTypeEnum.T2.getIntValue());
            request.setSourceOrderNo(changeLog.getOrderNo());
            request.setSourceDetailOrderNo(changeLog.getOrderNo() + changeLogDetail.getId());
            request.setSourceOrderType(SubjectEnum.T132.getCode());
            request.setSubject(SubjectEnum.T132.getCode());
            request.setMateInventoryId(changeLogDetail.getMateInventoryId());
            request.setLockQty(changeLogDetail.getQty());
            requests.add(request);
        }
        mateInventoryManager.releaseLockMateInventory(requests);
    }

    @Override
    public Page<MateInventoryOtherOutLogModeInfo> queryMateInventoryOtherOutLogMode(MateInventoryOtherOutLogQueryRequest request) {
        return mateInventoryOtherOutLogService.queryMateInventoryOtherOutLogMode(request);
    }
}